import ConfigParser
import os
import sys
import threading
import wx
from wx.lib.mixins.listctrl import CheckListCtrlMixin

import wowace

class AddonCheckListCtrl(wx.ListCtrl, CheckListCtrlMixin):
    def __init__(self, parent):
        wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)
        CheckListCtrlMixin.__init__(self)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated)
        #self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list)
        #self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.list)
        
        self.InsertColumn(0, "Name", width=200)
        self.InsertColumn(1, "Author", wx.LIST_FORMAT_RIGHT, width=130)
        self.InsertColumn(2, "Latest Version", wx.LIST_FORMAT_RIGHT, width=85)
        self.InsertColumn(3, "Local Version", wx.LIST_FORMAT_RIGHT, width=85)
        
        #self.SetColumnWidth(0, wx.LIST_AUTOSIZE)
        #self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
        #self.SetColumnWidth(2, wx.LIST_AUTOSIZE)
        #self.SetColumnWidth(3, wx.LIST_AUTOSIZE)
    
    def OnItemActivated(self, event):
        self.ToggleItem(event.m_itemIndex)

    # this is called by the base class when an item is checked/unchecked
    def OnCheckItem(self, index, flag):
        pass

class WowaceFrame(wx.Frame):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.CAPTION|wx.CLOSE_BOX|wx.MINIMIZE_BOX|wx.MAXIMIZE_BOX|wx.SYSTEM_MENU|wx.SIMPLE_BORDER|wx.RESIZE_BORDER|wx.NO_BORDER|wx.CLIP_CHILDREN
        kwds["size"] = (640, 600)
        wx.Frame.__init__(self, *args, **kwds)
        
        # Now create the Panel to put the other controls on.
        self.panel = WowacePanel(self)
        
        self.__set_properties()
        self.__do_layout()
    
    def __set_properties(self):
        self.SetTitle("wowace.py")
    
    def __do_layout(self):
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.panel, 0, wx.EXPAND, 0)
        self.Layout()

class WowacePanel(wx.Panel):
    def __init__(self, *args, **kwds):
        kwds["style"] = wx.TAB_TRAVERSAL
        wx.Panel.__init__(self, *args, **kwds)
        self.notebook = wx.Notebook(self, -1, style=0)
        
        self.notebook_update = wx.Panel(self.notebook, -1)
        self.update_text = wx.StaticText(self.notebook_update, -1, "There are no updates available.", style=wx.ALIGN_CENTRE|wx.ST_NO_AUTORESIZE)
        self.update_list = AddonCheckListCtrl(self.notebook_update)
        self.button_check = wx.Button(self.notebook_update, -1, "Check")
        self.button_update = wx.Button(self.notebook_update, -1, "Update")
        
        self.Bind(wx.EVT_BUTTON, self.thread_reload, self.button_check)
        self.Bind(wx.EVT_BUTTON, self.update_checked, self.button_update)
        
        self.notebook_install = wx.Panel(self.notebook, -1)
        self.install_text = wx.StaticText(self.notebook_install, -1, "There are no addons available.", style=wx.ALIGN_CENTRE|wx.ST_NO_AUTORESIZE)
        self.install_list = AddonCheckListCtrl(self.notebook_install)
        self.button_check2 = wx.Button(self.notebook_install, -1, "Check")
        self.button_install = wx.Button(self.notebook_install, -1, "Install")
        
        self.Bind(wx.EVT_BUTTON, self.thread_reload, self.button_check2)
        self.Bind(wx.EVT_BUTTON, self.add_or_remove, self.button_install)
        
        self.notebook_prefs = wx.Panel(self.notebook, -1)
        
        self.checkbox_externals = wx.CheckBox(self.notebook_prefs, -1, "Use externals")
        self.wowdir_text = wx.StaticText(self.notebook_prefs, -1, "World of Warcraft Addons directory", style=wx.ALIGN_CENTRE|wx.ST_NO_AUTORESIZE)
        self.textctrl_wowdir = wx.TextCtrl(self.notebook_prefs, -1)
        self.button_wowdir = wx.Button(self.notebook_prefs, -1, "Browse")
        self.wowace_text = wx.StaticText(self.notebook_prefs, -1, "WoWAce files", style=wx.ALIGN_CENTRE|wx.ST_NO_AUTORESIZE)
        self.textctrl_wowace = wx.TextCtrl(self.notebook_prefs, -1)
        
        self.button_save = wx.Button(self.notebook_prefs, -1, "Save")
        self.button_about = wx.Button(self.notebook_prefs, -1, "About")
        
        self.Bind(wx.EVT_BUTTON, self.save_prefs, self.button_save)
        self.Bind(wx.EVT_BUTTON, self.show_about, self.button_about)
        self.Bind(wx.EVT_BUTTON, self.browse_wowdir, self.button_wowdir)
        
        self.__set_properties()
        self.__do_layout()
        
        self.load_prefs()
        
        self.wowace = None
        self.thread = None
        self.thread_reload()

    def __set_properties(self):
        pass

    def __do_layout(self):
        # Arrange the update panel.
        sizer_update = wx.BoxSizer(wx.VERTICAL)
        sizer_update_buttons = wx.BoxSizer(wx.HORIZONTAL)
        
        sizer_update.Add(self.update_text, 0, wx.EXPAND, 0)
        sizer_update.Add(self.update_list, 8, wx.EXPAND, 0)
        sizer_update.Add(sizer_update_buttons, 1, wx.EXPAND, 0)
        
        sizer_update_buttons.Add(self.button_check, 4, wx.EXPAND, 0)
        sizer_update_buttons.Add((20,20), 1, wx.EXPAND, 0)
        sizer_update_buttons.Add(self.button_update, 4, wx.EXPAND, 0)
        
        self.notebook_update.SetSizer(sizer_update)
        
        # Arrange the install panel.
        sizer_install = wx.BoxSizer(wx.VERTICAL)
        sizer_install_buttons = wx.BoxSizer(wx.HORIZONTAL)
        
        sizer_install.Add(self.install_text, 0, wx.EXPAND, 0)
        sizer_install.Add(self.install_list, 8, wx.EXPAND, 0)
        sizer_install.Add(sizer_install_buttons, 1, wx.EXPAND, 0)
        
        sizer_install_buttons.Add(self.button_check2, 4, wx.EXPAND, 0)
        sizer_install_buttons.Add((20,20), 1, wx.EXPAND, 0)
        sizer_install_buttons.Add(self.button_install, 4, wx.EXPAND, 0)
        
        self.notebook_install.SetSizer(sizer_install)
        
        # Da prefs.
        
        sizer_prefs = wx.BoxSizer(wx.VERTICAL)
        sizer_wowace = wx.BoxSizer(wx.HORIZONTAL)
        sizer_wowdir = wx.BoxSizer(wx.HORIZONTAL)
        
        sizer_prefs.Add(self.checkbox_externals, 1, wx.CENTER, 0)
        sizer_wowace.Add(self.wowace_text, 1, wx.EXPAND, 0)
        sizer_wowace.Add(self.textctrl_wowace, 1, 0, 0)
        sizer_wowdir.Add(self.wowdir_text, 3, wx.EXPAND, 0)
        sizer_wowdir.Add(self.textctrl_wowdir, 2, 0, 0)
        sizer_wowdir.Add(self.button_wowdir, 1, 0, 0)
        sizer_prefs.Add(sizer_wowdir, 1, wx.EXPAND, 0)
        sizer_prefs.Add(sizer_wowace, 1, wx.EXPAND, 0)
        sizer_prefs.Add(self.button_save, 1, wx.EXPAND, 0)
        sizer_prefs.Add(self.button_about, 0, wx.ALIGN_RIGHT, 0)
        
        self.notebook_prefs.SetSizer(sizer_prefs)
        
        # Arrange the notebook itself.
        self.notebook.AddPage(self.notebook_update, "Update")
        self.notebook.AddPage(self.notebook_install, "Install")
        self.notebook.AddPage(self.notebook_prefs, "Settings")
        
        sizer_notebook = wx.BoxSizer(wx.VERTICAL)
        sizer_notebook.Add(self.notebook, 1, wx.EXPAND, 0)
        #sizer_notebook.Add(sizer_misc, 0, wx.EXPAND, 0)
        
        self.SetSizer(sizer_notebook)
        sizer_notebook.Fit(self)
    
    def thread_reload(self, event=None):
        if not self.thread or not self.thread.isAlive():
            self.thread = threading.Thread(target=self.reload_data)
            self.thread.start()
    
    def reload_data(self, flush=False):
        if not os.path.exists(self.config['wowace.wowdir']):
            self.notebook.SetSelection(2) # Go to the config panel.
            dlg = wx.MessageDialog(self, "Your World of Warcraft directory could not be accessed.  Please set its correct location now.", "Missing", wx.OK|wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return
        
        self.button_check.Disable()
        self.button_check2.Disable()
        self.button_update.Disable()
        self.button_install.Disable()
        self.update_text.SetLabel("LOADING")
        self.install_text.SetLabel("LOADING")
        
        try:
            if not flush and self.wowace:
                self.wowace.refresh()
            else:
                self.wowace = wowace.wowace(wowdir=self.config['wowace.wowdir'], wowace=self.config['wowace.wowace'], externals=bool(self.config['wowace.externals']))
        except wowace.urllib2.URLError, e:
            #This *probably* means the operation timed out.
            dlg = wx.MessageDialog(self, "Checking the server for addons caused an error.\nThe error is: %s" % e.reason, "Error!", wx.OK|wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
        except IOError, e:
            #Most likely, wow directory not found.
            dlg = wx.MessageDialog(self, "An IO error was detected.\nThe error is: %s" % e.strerror, "Error!", wx.OK|wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
        else:
            self.redraw_update()
            self.redraw_install()
        
        self.button_check.Enable()
        self.button_check2.Enable()
    
    def redraw_update(self):
        # For the update panel:
        addons_to_update = self.wowace.addons_to_be_updated()
        self.update_list.DeleteAllItems()
        self.updateindex = {}
        if len(addons_to_update) > 0:
            self.update_text.SetLabel("There are %d updates to install." % len(addons_to_update))
            i = 1
            for addon in addons_to_update:
                data = self.wowace.remoteaddons[addon]
                index = self.update_list.InsertStringItem(sys.maxint, addon)
                self.update_list.SetStringItem(index, 1, data['author'])
                self.update_list.SetStringItem(index, 2, data['version'])
                self.update_list.SetStringItem(index, 3, self.wowace.localaddons[addon])
                self.update_list.SetItemData(index, i)
                self.update_list.CheckItem(index)
                
                self.updateindex[i] = addon
                i = i + 1
            self.button_update.Enable()
        else:
            self.update_text.SetLabel("There are no updates available.")
            self.button_update.Disable()
    
    def redraw_install(self):
        # For the install panel:
        all_addons = self.wowace.remoteaddons.items()
        all_addons.sort()
        self.install_list.DeleteAllItems()
        self.addonindex = {}
        if len(all_addons) > 0:
            self.install_text.SetLabel("There are %d addons available." % len(all_addons))
            i = 1
            for addon in all_addons:
                data = addon[1]
                index = self.install_list.InsertStringItem(sys.maxint, addon[0])
                self.install_list.SetStringItem(index, 1, data['author'])
                self.install_list.SetStringItem(index, 2, data['version'])
                self.install_list.SetStringItem(index, 3, self.wowace.localaddons.get(addon[0], ''))
                self.install_list.SetItemData(index, i)
                
                if self.wowace.localaddons.has_key(addon[0]):
                    self.install_list.CheckItem(index)
                
                self.addonindex[i] = addon[0]
                i = i + 1
            self.button_install.Enable()
        else:
            self.install_text.SetLabel("There are no addons available.")
            self.button_install.Disable()

    def update_checked(self, event):
        self.wowace.batchupdating = True
        for i in range(self.update_list.GetItemCount()):
            addon = self.updateindex[i+1]
            if self.update_list.IsChecked(i):
                #print "update %s" % addon
                self.wowace.update_addon(addon)
        self.wowace.batchupdating = False
        self.wowace.save_local_addons()
        self.redraw_update()
    
    def add_or_remove(self, event):
        self.wowace.batchupdating = True
        for i in range(self.install_list.GetItemCount()):
            addon = self.addonindex[i+1]
            if self.install_list.IsChecked(i):
                if not self.wowace.localaddons.has_key(addon):
                    #print "install %s" % addon
                    self.wowace.update_addon(addon)
            else:
                if self.wowace.localaddons.has_key(addon):
                    #print "remove %s" % addon
                    self.wowace.remove_addon(addon)
        self.wowace.batchupdating = False
        self.wowace.save_local_addons()
        self.redraw_install()
    
    def show_about(self, event):
        ab = wx.AboutDialogInfo()
        ab.SetName("wowace.py")
        ab.SetDevelopers([wowace.__author__,])
        ab.SetLicense(wowace.__license__)
        ab.SetVersion(wowace.__version__)
        
        wx.AboutBox(ab)
    
    def browse_wowdir(self, event):
        dlg = wx.DirDialog(self, "Choose your WoW Addons directory:", style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST)
        if dlg.ShowModal() == wx.ID_OK:
            self.textctrl_wowdir.SetValue(dlg.GetPath())
        dlg.Destroy()
    
    _defaults = {
        'wowace.wowdir': wowace.get_wowdir(),
        'wowace.wowace': wowace.default_wowace,
        'wowace.externals': wowace.default_externals and '1' or '',
    }
    def load_prefs(self, event = None):
        self.config = self._defaults.copy()
        cp = ConfigParser.SafeConfigParser()
        cp.read('wowacepy.ini')
        for sec in cp.sections():
            name = sec.lower()
            for opt in cp.options(sec):
                self.config[name+"."+opt.lower()] = cp.get(sec, opt).strip()
        
        self.checkbox_externals.SetValue(bool(self.config['wowace.externals']))
        self.textctrl_wowdir.SetValue(self.config['wowace.wowdir'])
        self.textctrl_wowace.SetValue(self.config['wowace.wowace'])
        
    
    def save_prefs(self, event):
        externals = self.checkbox_externals.GetValue() and '1' or ''
        wowdir = self.textctrl_wowdir.GetValue()
        wowace = self.textctrl_wowace.GetValue()
        
        do_reload = False
        if self.config['wowace.externals'] != externals or self.config['wowace.wowdir'] != wowdir or self.config['wowace.wowace'] != wowace:
            do_reload = True

        self.config['wowace.externals'] = externals
        self.config['wowace.wowdir'] = wowdir
        self.config['wowace.wowace'] = wowace
        
        cp = ConfigParser.SafeConfigParser()
        for item in self.config:
            sec, opt = item.split('.')
            if not cp.has_section(sec):
                cp.add_section(sec)
            cp.set(sec, opt, self.config[item])
        cpf = open('wowacepy.ini', 'w')
        cp.write(cpf)
        cpf.close()
        
        if do_reload:
            # Need to reload the wowace object.
            self.thread_reload(True)

if __name__ == "__main__":
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    waframe = WowaceFrame(None, -1, "")
    app.SetTopWindow(waframe)
    waframe.Show()
    app.MainLoop()

